import OpenAI from 'openai';
import process from 'process';
import { FakeApi } from '@wowon/utils';
import { userList } from './access/user';
import { getCurrentUser } from '../auth-center';

const initTabs = userList.getList().map((author) => {
  return {
    title: '使用js用伪随机实现一些有趣的功能',
    model: 'qwq-32b',
    authorId: author.id,
  };
});

const tabList = new FakeApi(initTabs, {
  queryType: {
    title: 'like',
    authorId: 'is',
  },
});

const initData = userList.getList().map((author) => {
  return {
    tabId: tabList.getItem({ authorId: author.id }).id,
    question: '使用js用伪随机实现一些有趣的功能',
    think:
      '<think>嗯，用户让我用JavaScript用伪随机实现一些有趣的功能。首先，我需要理解用户的需求。他们可能想要一些有趣的例子，展示如何利用JavaScript的Math.random()函数来生成看似随机但实际上可预测的结果。伪随机通常指的是使用确定性的算法生成的随机数，虽然看起来随机，但可以通过种子来复现结果。不过，JavaScript的Math.random()本身是伪随机的，因为它基于种子，但种子通常由系统时间初始化，所以每次运行都会不同。\n\n用户可能希望看到不同的应用场景，比如游戏、艺术效果、生成内容等。我需要想几个有趣的例子，每个例子都能展示伪随机的不同用途。比如生成随机颜色、随机迷宫、随机故事生成器、虚拟宠物、密码生成器、随机艺术图案等。\n\n首先，我需要确保每个例子都简单易懂，代码清晰，并且有注释解释。同时，要考虑到伪随机的特性，比如如何设置种子来复现结果，可能在某些例子中需要实现一个可重复的随机数生成器，比如使用Math.random()但用seedrandom库来设置种子。不过用户可能希望不依赖外部库，所以可能需要自己实现一个简单的线性同余生成器（LCG）作为示例。\n\n然后，我需要考虑每个例子的具体实现。例如，随机颜色生成可以通过Math.random()生成RGB值，随机迷宫可以用递归回溯算法，但需要随机选择方向。虚拟宠物可以随机变化状态，比如饥饿值和心情值。随机故事生成器可能需要根据随机数选择不同的故事片段组合。\n\n还要注意，伪随机在游戏中的应用，比如RPG中的敌人生成或物品掉落。另外，可能需要解释为什么使用伪随机，比如可复现性对于调试或游戏存档的重要性。\n\n接下来，我需要组织这些例子，确保每个都有代码和简要说明。可能需要先写一个简单的伪随机数生成器，然后用它来实现各个功能。不过JavaScript的Math.random()已经足够，但用户可能希望看到如何自定义伪随机序列，比如通过设置种子。\n\n例如，可以先展示如何用Math.random()生成随机颜色，然后展示一个简单的可重复的例子，比如用seedrandom库，但考虑到用户可能不想引入外部库，可以自己实现一个简单的种子生成器。\n\n或者，使用Math.random()但通过设置种子函数，比如通过Math.seedrandom函数，但需要说明需要包含该库。或者，用一个更基础的方法，比如给定种子，然后使用一个伪随机算法来生成数字。\n\n例如，线性同余生成器的公式：Xn+1 = (a*Xn + c) mod m。可以自己实现一个简单的，然后用种子初始化。\n\n这样用户就可以通过设置种子来获得可重复的随机序列。这可能是一个有趣的点，比如生成相同的迷宫或图案。\n\n然后，我需要为每个例子编写代码，并解释其工作原理。例如，随机迷宫生成可能需要先初始化一个二维数组，然后使用递归回溯算法，其中随机选择方向来打通墙壁。\n\n另一个例子是虚拟宠物，宠物的状态随时间变化，比如每隔一段时间随机变化饥饿或心情，可以使用setTimeout和随机数来实现。\n\n随机故事生成器可以基于几个故事片段，随机组合成一个故事，比如随机选择开头、中间和结尾。\n\n密码生成器可以生成一定长度的随机密码，包含大小写字母、数字和符号。\n\n随机艺术图案可能用canvas，绘制随机形状或颜色。\n\n此外，可能需要考虑性能问题，比如在生成大量数据时使用Math.random()的效率，但大多数情况下不会有问题。\n\n现在，我需要确保每个例子都有足够的解释，让用户明白如何工作，并且能够运行。可能需要先列出几个例子，然后详细说明每个的代码和思路。\n\n比如第一个例子：随机颜色生成器，可以生成一个十六进制颜色字符串。代码可以很简单，用Math.random()生成RGB值，然后转换为十六进制。\n\n第二个例子：可重复的随机数生成，使用seedrandom库，但如果没有，可以自己实现一个简单的，比如：\n\nfunction setSeed(seed) {\n  seed = (seed * 9301 + 49297) % 233280;\n  return seed / 233280.0;\n}\n\n然后每次调用setSeed(seed)来得到下一个随机数。不过这可能需要更多的代码，但用户可能需要一个简单的例子。\n\n第三个例子：虚拟宠物，使用setInterval来每秒更新状态，用随机数决定是否增加饥饿或心情。\n\n第四个例子：随机迷宫生成，使用递归回溯算法，其中在选择下一个方向时随机排列方向顺序。\n\n第五个例子：随机故事生成，根据随机数选择不同的段落组合。\n\n第六个例子：密码生成器，根据长度和字符集生成密码。\n\n可能还要考虑其他有趣的应用，比如随机音乐生成，但可能需要更复杂的代码，或者简单的随机数游戏，比如猜数字。\n\n最后，我需要确保每个例子都有代码片段，并且解释清楚，这样用户可以复制并运行，看到效果。同时，要说明伪随机的原理，比如为什么使用Math.random()是伪随机，以及如何设置种子来复现结果。',
    content:
      "</think>以下是几个使用 JavaScript 伪随机数实现的有趣功能示例，每个示例都展示了不同场景下的应用：\n\n---\n\n### 1. **可重复的随机数生成器（使用种子）**\n伪随机数可以通过设置种子来复现结果，这对游戏存档或调试非常有用。这里用简单的线性同余生成器 (LCG) 实现：\n\n```javascript\nlet seed = 12345; // 种子值\n\nfunction random() {\n  seed = (seed * 9301 + 49297) % 233280;\n  return seed / 233280.0;\n}\n\nconsole.log(random()); // 0.7432...（每次种子相同则结果相同）\nconsole.log(random()); // 0.5821...\n```\n\n---\n\n### 2. **随机颜色生成器**\n生成随机十六进制颜色代码：\n\n```javascript\nfunction getRandomColor() {\n  const letters = '0123456789ABCDEF';\n  let color = '#';\n  for (let i = 0; i < 6; i++) {\n    color += letters[Math.floor(Math.random() * 16)];\n  }\n  return color;\n}\n\ndocument.body.style.backgroundColor = getRandomColor(); // 随机背景色\n```\n\n---\n\n### 3. **虚拟宠物（状态随机变化）**\n模拟一个虚拟宠物的饥饿和心情值，每隔几秒随机变化：\n\n```javascript\nclass VirtualPet {\n  constructor(name) {\n    this.name = name;\n    this.hunger = 0;\n    this.mood = 100;\n    this.updateInterval = setInterval(() => {\n      this.hunger += Math.random() * 0.2; // 随机增加饥饿值\n      this.mood -= Math.random() * 0.1;   // 随机降低心情值\n      this.printStatus();\n    }, 1000);\n  }\n\n  printStatus() {\n    console.log(`宠物 ${this.name}: 饥饿度 ${this.hunger.toFixed(1)}%，心情 ${this.mood.toFixed(1)}%`);\n  }\n}\n\nconst pet = new VirtualPet('小喵'); // 运行后每秒输出状态变化\n```\n\n---\n\n### 4. **随机迷宫生成器**\n使用递归回溯算法生成迷宫，方向选择随机化：\n\n```javascript\nfunction generateMaze(width, height) {\n  const maze = Array(height)\n    .fill()\n    .map(() => Array(width).fill(1));\n  const dirs = [[0, 2], [2, 0], [0, -2], [-2, 0]];\n\n  function visit(x, y) {\n    maze[y][x] = 0;\n    dirs.sort(() => 0.5 - Math.random()); // 随机排列方向\n    for (const [dx, dy] of dirs) {\n      const nx = x + dx;\n      const ny = y + dy;\n      if (nx >= 0 && nx < width && ny >= 0 && ny < height && maze[ny][nx] === 1) {\n        maze[(y + ny) / 2][(x + nx) / 2] = 0;\n        visit(nx, ny);\n      }\n    }\n  }\n  visit(1, 1);\n  return maze;\n}\n\nconst maze = generateMaze(11, 11); // 输出一个 11x11 的迷宫\nconsole.table(maze);\n```\n\n---\n\n### 5. **随机故事生成器**\n根据随机选择的片段组合成一个故事：\n\n```javascript\nconst storyParts = {\n  start: ['在一个雨夜', '在未来的城市里', '当时间停止时'],\n  middle: ['我发现了神秘的日记', '突然出现了一个陌生人', '收到了一封加密邮件'],\n  end: ['最终揭开了真相', '但代价是失去记忆', '却陷入更深的谜团']\n};\n\nfunction generateStory() {\n  return `${storyParts.start[Math.floor(Math.random() * 3)]}，` +\n         `${storyParts.middle[Math.floor(Math.random() * 3)]}，` +\n         `${storyParts.end[Math.floor(Math.random() * 3)]}。`;\n}\n\nconsole.log(generateStory());\n// 输出示例：在未来的城市里，突然出现了一个陌生人，最终揭开了真相。\n```\n\n---\n\n### 6. **随机密码生成器**\n生成指定长度的强密码（包含大小写字母、数字和符号）：\n\n```javascript\nfunction generatePassword(length = 12) {\n  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+';\n  let password = '';\n  for (let i = 0; i < length; i++) {\n    password += chars.charAt(Math.floor(Math.random() * chars.length));\n  }\n  return password;\n}\n\nconsole.log(generatePassword(16)); // 输出类似 \"aB3$zX7!qR9@kL2&\"\n```\n\n---\n\n### 7. **随机艺术图案（Canvas）**\n在 Canvas 上绘制随机几何图形：\n\n```javascript\nfunction drawRandomArt(canvasId) {\n  const canvas = document.getElementById(canvasId);\n  const ctx = canvas.getContext('2d');\n  ctx.fillStyle = getRandomColor();\n  ctx.fillRect(0, 0, canvas.width, canvas.height);\n\n  for (let i = 0; i < 50; i++) {\n    ctx.beginPath();\n    ctx.arc(\n      Math.random() * canvas.width,\n      Math.random() * canvas.height,\n      Math.random() * 30,\n      0,\n      Math.PI * 2\n    );\n    ctx.fillStyle = getRandomColor();\n    ctx.fill();\n  }\n}\n\ndrawRandomArt('myCanvas'); // 需要一个 id 为 myCanvas 的 Canvas 元素\n```\n\n---\n\n### 8. **猜数字游戏**\n玩家猜测一个随机生成的数字：\n\n```javascript\nfunction guessNumber() {\n  const target = Math.floor(Math.random() * 100) + 1;\n  const guess = parseInt(prompt(\"猜一个 1-100 的数字：\"), 10);\n\n  if (isNaN(guess)) return alert(\"请输入数字！\");\n  if (guess === target) alert(\"恭喜你猜对了！\");\n  else if (guess < target) alert(\"太小了，正确答案是 \" + target);\n  else alert(\"太大了，正确答案是 \" + target);\n}\n\nguessNumber(); // 在浏览器中运行会弹出输入框\n```\n\n---\n\n### 伪随机的关键点\n- **Math.random()**：JavaScript 内置的伪随机函数，基于种子（默认由系统时间初始化）。\n- **种子可复现性**：通过自定义种子函数（如示例 1），可确保相同种子生成相同序列。\n- **应用场景**：游戏、艺术、数据生成、测试用例等。\n\n这些示例展示了如何利用伪随机性创造有趣且可控制的效果，同时保持代码简洁易懂。",
    author,
    authorId: author.id,
  };
});

const promptList = new FakeApi(initData, {
  queryType: {
    tabId: 'is',
    question: 'like',
    authorId: 'is',
  },
  sort: (x, y) => new Date(x.createTime) - new Date(y.createTime),
});

const apiKey = process.env.DASHSCOPE_API_KEY;

// 初始化 openai 客户端
const openai = new OpenAI({
  apiKey,
  baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
});

async function savePrompt(tabId, question, model, think, content, author) {
  think += '</think>';
  content = content.replace(/^<\/think>/, '');
  if (!tabId) {
    const tabRes = await tabList.create({ title: question, model, authorId: author.id });
    tabId = tabRes.data.id;
  }
  await promptList.create({ tabId, question, think, content, author, authorId: author.id });
}

export default {
  'POST /mock/prompt': async (req, res) => {
    const currentUser = getCurrentUser(req);
    if (!currentUser) {
      res.statusCode = 401;
      res.json({ code: '-1', message: '权限不足' });
      return;
    }
    const author = currentUser.data;

    const tabId = req.body.tabId;
    const model = req.body.model || 'qwq-32b';
    const question = req.body.q;
    const role = 'user';
    const result = await promptList.list({ authorId: author.id, tabId });
    let think = '';
    let content = '';
    try {
      // 设置流式响应头
      res.setHeader('Content-Type', 'application/x-ndjson');
      res.setHeader('Transfer-Encoding', 'chunked');

      if (!apiKey) {
        res.write('[Error] 请联系管理员设置 `.env` 环境变量 `DASHSCOPE_API_KEY`！');
        res.end();
        return;
      }

      if (!question) {
        res.write('[Error] 请输入问题！');
        res.end();
        return;
      }

      const stream = await openai.chat.completions.create({
        model,
        messages: result.list.map((item) => ({ role, content: item.content })).concat({ role, content: question }),
        stream: true,
      });

      let isReasoning = false;
      for await (const chunk of stream) {
        if (!chunk.choices?.length) continue;

        const delta = chunk.choices[0].delta;
        let answer = '';
        // 优先发送推理内容，然后是正式回答
        if (delta.reasoning_content) {
          answer = (isReasoning ? '' : '<think>') + delta.reasoning_content;
          if (!isReasoning) isReasoning = true;
          think += answer;
          res.write(answer);
        } else if (delta.content) {
          answer = (!isReasoning ? '' : '</think>') + delta.content;
          if (isReasoning) isReasoning = false;
          content += answer;
          res.write(answer);
        }
      }
      savePrompt(tabId, question, model, think, content, author);
    } catch (error) {
      console.error('Error:', error);
      await savePrompt(tabId, question, model, think, content, author);
      if (!res.headersSent) {
        res.status(500).json({ error: 'Internal Server Error' });
      } else {
        res.end(); // 如果已经开始发送数据，直接结束连接
      }
    }
  },
  // ---------------- 对话 tabs 操作 ----------------
  'GET /mock/prompt/tabs/list': async (req, res) => {
    const currentUser = getCurrentUser(req);
    if (!currentUser) {
      res.statusCode = 401;
      res.json({ code: '-1', message: '权限不足' });
      return;
    }
    const author = currentUser.data;
    const result = await tabList.list({ authorId: author.id, ...req.query });
    res.json(result);
  },
  'POST /mock/prompt/tabs/update': async (req, res) => {
    const currentUser = getCurrentUser(req);
    if (!currentUser) {
      res.statusCode = 401;
      res.json({ code: '-1', message: '权限不足' });
      return;
    }
    const result = await tabList.update(req.body);
    res.json(result);
  },
  'POST /mock/prompt/tabs/remove': async (req, res) => {
    const currentUser = getCurrentUser(req);
    if (!currentUser) {
      res.statusCode = 401;
      res.json({ code: '-1', message: '权限不足' });
      return;
    }
    const result = await tabList.remove(req.body);
    res.json(result);
  },
  // ---------------- 对话记录操作 ----------------
  'GET /mock/prompt/query': async (req, res) => {
    const currentUser = getCurrentUser(req);
    if (!currentUser) {
      res.statusCode = 401;
      res.json({ code: '-1', message: '权限不足' });
      return;
    }
    const author = currentUser.data;
    const result = await promptList.query({ authorId: author.id, ...req.query });
    res.json(result);
  },
};
